package com.smartcar.encode;

import com.smartcar.enums.CarDirection;
import lombok.extern.slf4j.Slf4j;

/**
 * 小车编码器
 * 对应原HarmonyOS的CarEncode
 */
@Slf4j
public class CarEncode {

    private static final String TAG = "CarEncode";
    private static final boolean isDebug = true;

    /**
     * 开始循迹
     */
    public static String trackingOpenEncode() {
        return baseEncode("63");
    }

    /**
     * 关闭循迹
     */
    public static String trackingCloseEncode() {
        return baseEncode("64");
    }

    /**
     * 拍摄图片
     */
    public static String takePhotosEncode() {
        return baseEncode("60");
    }

    /**
     * 开始录像
     */
    public static String startRecordingEncode() {
        return baseEncode("61");
    }

    /**
     * 结束录像
     */
    public static String closeRecordingEncode() {
        return baseEncode("62");
    }

    /**
     * 车辆控制编码
     * @param speedX -100 ~ 100
     * @param speedY -100 ~ 100
     */
    public static String ctrlCarEncode(int speedX, int speedY) {
        // 四舍五入
        int sendX = Math.round(speedX);
        int sendY = Math.round(speedY);

        // 调试模式下输出信息
        if (isDebug) {
            log.debug("{} ctrlCarEncode speedX = {} speedY = {}", TAG, speedX, speedY);
        }

        if (sendX < 0) sendX += 256;
        if (sendY < 0) sendY += 256;

        // 调试模式下输出信息
        if (isDebug) {
            log.debug("{} ctrlCarEncode speedX = {} speedY = {} sendX = {} sendY = {}", 
                    TAG, speedX, speedY, sendX, sendY);
        }

        return baseEncode("10", 
                numberToHex(sendX, 2) + numberToHex(sendY, 2));
    }

    /**
     * 按钮车辆控制
     */
    public static String buttonCarEncode(CarDirection direction) {
        return baseEncode("15", numberToHex(direction.getValue(), 2));
    }

    /**
     * 四轮单独控制
     */
    public static String upSpeedCarEncode(int l1, int l2, int r1, int r2) {
        // 格式化函数
        l1 = Math.round(l1); // 四舍五入
        if (l1 < 0) l1 += 256; // 如果是负数那么格式化成正数
        
        l2 = Math.round(l2);
        if (l2 < 0) l2 += 256;
        
        r1 = Math.round(r1);
        if (r1 < 0) r1 += 256;
        
        r2 = Math.round(r2);
        if (r2 < 0) r2 += 256;

        // 返回编码信息
        return baseEncode("21",
                numberToHex(l1, 2),
                numberToHex(l2, 2),
                numberToHex(r1, 2),
                numberToHex(r2, 2));
    }

    /**
     * 通用基础编码能力
     */
    private static String baseEncode(String type, String... datas) {
        StringBuilder info = new StringBuilder();
        for (String data : datas) {
            info.append(data);
        }

        // 8为基础数据长度
        String size = numberToHex(info.length() + 2, 2);

        // 数据拼接
        StringBuilder code = new StringBuilder();
        code.append("01") // 车辆类型
            .append(type) // 命令标记
            .append(size) // 数据长度
            .append(info); // 数据主体

        code.append(numberToHex(getCheckChecksum(code.toString()), 2));

        // 添加开始结束符
        code.insert(0, "$").append("#");

        // 调试模式下输出信息
        if (isDebug) {
            log.debug("{} baseEncode {}", TAG, code);
        }

        return code.toString();
    }

    /**
     * 数字转十六进制
     */
    private static String numberToHex(int num, int len) {
        String hex = Integer.toHexString(num);
        while (hex.length() < len) {
            hex = "0" + hex;
        }
        return hex.toUpperCase();
    }

    /**
     * 数据校验运算
     */
    private static int getCheckChecksum(String data) {
        log.debug("getCheckChecksum {}", data);
        // 初始化校验和变量
        int dataSize = data.length();
        int calculatedChecksum = 0;

        // 计算校验和（每次处理两个字符）
        for (int i = 0; i < dataSize; i += 2) {
            // 每次处理两个字符（一个字节）
            String byteStr = data.substring(i, Math.min(i + 2, dataSize));
            int byteValue = Integer.parseInt(byteStr, 16);
            calculatedChecksum = (calculatedChecksum + byteValue) % 256;
        }
        // 返回校验值状态
        return calculatedChecksum;
    }

    /**
     * 十六进制转数字
     */
    private static int hexToNumber(String hexString) {
        return Integer.parseInt(hexString, 16);
    }
} 